package main

import "fmt"

func main() {

	patientHealthHandler := StartHandler{}

	patient := &Patient{
		Name:              "abc",
	}
	patientHealthHandler.SetNext(&Reception{}).
		SetNext(&Clinic{}).
		SetNext(&Cashier{}).
		SetNext(&Pharmacy{})

	if err := patientHealthHandler.Execute(patient); err != nil{
		fmt.Println("fail ! Error:"+err.Error())
	}

	fmt.Println("success")

}

type PatientHandler interface {
	Execute(*Patient) error
	SetNext(handler PatientHandler) PatientHandler
	Do(*Patient) error
}

//Next 充当抽象类 实现公共方法，抽象方法不实现，留给实现类自己实现
type Next struct {
	nextHandler PatientHandler
}

func (n *Next) SetNext(handler PatientHandler) PatientHandler{
	n.nextHandler = handler
	return handler
}

func (n *Next) Execute(patient *Patient) (err error){
	//调用不到外部类型的Do方法，所以Next 不能实现Do方法
	if n.nextHandler != nil{
		if err = n.nextHandler.Do(patient); err != nil{
			return err
		}
		return n.nextHandler.Execute(patient)
	}
	return
}

type Patient struct {
	Name string
	RegistrationDone bool
	DoctorCheckUpDone bool
	MedicineDone bool
	PaymentDone bool
}

//Reception 挂号处理器
type Reception struct {
	Next
}

func (re *Reception) Do(p *Patient)(err error){
	if p.RegistrationDone {
		fmt.Println("Patient registration already done")
		return
	}

	fmt.Println("Reception registering patient")
	p.RegistrationDone = true
	return
}

//Clinic 诊室处理器--用于医生给病人看病
type Clinic struct {
	Next
}

func (cl *Clinic) Do(p *Patient)(err error){
	if p.DoctorCheckUpDone {
		fmt.Println("doctor checkup already done")
		return
	}
	fmt.Println("Doctor checking patient")
	p.DoctorCheckUpDone = true
	return
}
// Cashier 收费处处理器
type Cashier struct {
	Next
}

func (c *Cashier) Do( patient *Patient)(err error){
	if patient.PaymentDone {
		fmt.Println("Payment Done")
		return
	}
	fmt.Println("Cashier getting money from patient")
	patient.PaymentDone = true
	return
}

type Pharmacy struct {
	Next
}

func (m *Pharmacy) Do(patient *Patient) (err error){
	if patient.MedicineDone {
		fmt.Println("Medicine already given to patient")
		return
	}
	fmt.Println("Pharmacy giving medicine to patient")
	patient.MedicineDone = true
	return
}

type StartHandler struct {
	Next
}

func (h *StartHandler) Do (c* Patient) (err error){
	return
}

/*职责链模式所拥有的特点让流程中的每个处理节点都只需关注满足自己处理条件的请求进行处理即可
对于不感兴趣的请求，会直接转发给下一个节点对象进行处理。
另外职责链也可以设置中止条件，针对我们文中的例子就是在Execute方法里加判断
一旦满足中止后就不再继续往链路的下级节点传递请求。Gin 的中间件的abort方法就是按照这个原理实现的
同时这也是职责链跟装饰器模式的一个区别，装饰器模式无法在增强实体的过程中停止，只能执行完整个装饰链路。

 */

